// This file is part of Module Proxy.

// Module Proxy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Module Proxy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Module Proxy.  If not, see <https://www.gnu.org/licenses/>.


//         Copyright (C) 2021 - 2030  关中麦客  
//         All rights reserved
//
//         main.rs
//         socket服务，调用ffmpeg将rtsp转换为hls。
//         socket服务需要http中间件module proxy支持，https://gitee.com/dyf029/module-proxy
//
//         created by 关中麦客 1036038462@qq.com

// use log;
// use log4rs;
use log::LevelFilter;
use log4rs::encode::pattern::PatternEncoder;
use log4rs::config::{Appender, Config, Root};
use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
use log4rs::filter::threshold::ThresholdFilter;
use log4rs::append::rolling_file::RollingFileAppender;

use tokio::net::{TcpListener};
use once_cell::sync::OnceCell;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::Path;

mod conf;
mod process;
mod cache;
mod util;
mod file;

static _HOME_PATH: OnceCell<String> = OnceCell::new();   //全局变量HOME_PATH

#[tokio::main]
async fn main() 
{
    //获得HOME_PATH------------
    init_home_path();
    println!("HOME_PATH: {}", home_path());

    //加载配置文件------------
    if let Err(err_str) = conf::load()
    {
        println!("Error: {}", err_str);
        std::process::exit(1);   //exit
    }

    //创建输出目录
    if !create_output_path()
    {
        println!("Error: Can't create dir {}", conf::out_path());
        std::process::exit(1);   //exit
    }

    //初始化log4rs------------
    let log_level = conf::log_level();  //日志级别
    let lvl = match log_level{
        "warn"  => LevelFilter::Warn,
        "error" => LevelFilter::Error,
        _       => LevelFilter::Info,
    };
    log_init(lvl);

    // Cache -------------
    cache::init();

    // // 任务超时检测线程 -------------
    // tokio::spawn(async move {
    //     process::check_timeout().await;
    // });
    

    // TCP 侦听------------
    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), conf::server_port());
    let listener = TcpListener::bind(addr).await.unwrap();

    println!("");
    println!("===============================================================");
    println!("RTSP -> HLS Socket Service V{} start...", conf::version());
    println!("Listening on {}", addr);
    println!("Log Level: {}", lvl);
    println!("out path: {}", conf::out_path());
    println!("===============================================================");
    println!("");

    log::info!("");
    log::info!("===============================================================");
    log::info!("RTSP -> HLS Socket Service V{} start...", conf::version());
    log::info!("Listening on {}", addr);
    log::info!("Log Level: {}", lvl);
    log::info!("out path: {}", conf::out_path());
    log::info!("===============================================================");
    log::info!("");

    loop 
    {
        // accept
        let (socket, _) = listener.accept().await.unwrap();
        process::do_socket(socket).await;
    }
}


//init HOME_PATH
fn init_home_path()
{
    if let Ok(exe_path) = std::env::current_exe()               //exe路径
    {
        if let Some(parent_path) = exe_path.parent()            //exe所在目录
        {
            if let Some(parent_path) = parent_path.parent()     //上一级目录
            {
                if let Some(home_path) = parent_path.to_str()
                {
                    _HOME_PATH.get_or_init(||{
                        home_path.to_string()
                    });    
                    return;                
                }
            }                        
        }
    }

    println!("Error: Can't get Module Proxy home path.");
    std::process::exit(1);
}

/// 获得HOME_PATH
pub fn home_path() -> &'static String
{
    _HOME_PATH.get().unwrap()
}

/// 日志初始化
fn log_init(lvl: LevelFilter)
{
    //日志目录
    let home = home_path();
    let path = Path::new(home);
    let log_path = path.join("logs");
    //日志文件
    let mut file_path = log_path.clone();
    file_path.push("rtsp2hls.log");
    let filename = file_path.to_str().unwrap();
    let filename = filename.replace("\\", "/");
    //备份文件
    let mut bak_path = log_path.clone();
    bak_path.push("rtsp2hls{}.log");
    let bakfilename = bak_path.to_str().unwrap();
    let bakfilename = bakfilename.replace("\\", "/");

    //log文件备份数量
    let window_size = 5; 
    let fixed_window_roller = 
        FixedWindowRoller::builder().build(&bakfilename, window_size).unwrap();

    //log文件大小
    let size_limit = 10 * 1024 * 1024; // 循环日志文件最大10M
    let size_trigger = SizeTrigger::new(size_limit);

    let compound_policy = CompoundPolicy::new(Box::new(size_trigger),Box::new(fixed_window_roller));

    let file = RollingFileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}")))
        .build(filename, Box::new(compound_policy))
        .unwrap();

    let config = Config::builder()
        .appender(
            Appender::builder()
                .filter(Box::new(ThresholdFilter::new(LevelFilter::Info)))
                .build("file", Box::new(file))
        )
        .build(
            Root::builder().appender("file").build(lvl)
        )
        .unwrap();

    log4rs::init_config(config).unwrap();
}

///创建输出目录
fn create_output_path() -> bool
{
    let path_str = conf::out_path();
    let path = Path::new(path_str);
    if path.is_dir()
    {
        return true;  //目录存在
    }

    if let Ok(_) = std::fs::create_dir_all(path)
    {
        return true;    //目录创建成功
    }

    false
}